import mongoose, { Schema, Document, Model } from 'mongoose';

/**
 * 小组接口定义
 * 定义小组的基本属性和结构
 */
export interface IGroup {
  name: string;           // 小组名称
  description?: string;   // 小组描述
  departmentId: mongoose.Types.ObjectId; // 所属部门ID
  leaderId?: mongoose.Types.ObjectId;    // 小组组长ID
  status: number;         // 状态：1-正常，0-禁用
  createdAt?: Date;       // 创建时间
  updatedAt?: Date;       // 更新时间
}

/**
 * 小组文档接口
 * 继承IGroup接口和mongoose Document接口
 */
export interface IGroupDocument extends IGroup, Document {
  /**
   * 将小组文档转换为JSON格式
   * @returns 安全的小组数据对象
   */
  toJSON(): any;
}

/**
 * 小组模型接口
 * 定义小组模型的静态方法
 */
export interface IGroupModel extends Model<IGroupDocument> {
  /**
   * 根据小组名称查找小组
   * @param name 小组名称
   * @returns 小组文档或null
   */
  findByName(name: string): Promise<IGroupDocument | null>;

  /**
   * 根据部门ID查找小组列表
   * @param departmentId 部门ID
   * @returns 小组文档数组
   */
  findByDepartment(departmentId: mongoose.Types.ObjectId): Promise<IGroupDocument[]>;

  /**
   * 根据组长ID查找小组
   * @param leaderId 组长ID
   * @returns 小组文档或null
   */
  findByLeader(leaderId: mongoose.Types.ObjectId): Promise<IGroupDocument | null>;

  /**
   * 根据状态查找小组列表
   * @param status 状态值
   * @returns 小组文档数组
   */
  findByStatus(status: number): Promise<IGroupDocument[]>;
}

/**
 * 小组数据模型Schema定义
 * 定义小组的数据结构、验证规则和索引
 */
const GroupSchema = new Schema<IGroupDocument>({
  // 小组名称，必填，长度限制
  name: {
    type: String,
    required: [true, '小组名称不能为空'],
    trim: true,
    minlength: [2, '小组名称至少2个字符'],
    maxlength: [50, '小组名称不能超过50个字符'],
    match: [/^[\u4e00-\u9fa5a-zA-Z0-9\s\-_]+$/, '小组名称只能包含中文、英文、数字、空格、横线和下划线']
  },
  
  // 小组描述，可选
  description: {
    type: String,
    trim: true,
    maxlength: [200, '小组描述不能超过200个字符']
  },
  
  // 所属部门ID，必填
  departmentId: {
    type: Schema.Types.ObjectId,
    ref: 'Department',
    required: [true, '所属部门不能为空']
  },
  
  // 小组组长ID，可选
  leaderId: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  
  // 状态，必填，只能是0或1
  status: {
    type: Number,
    required: [true, '小组状态不能为空'],
    enum: [0, 1],
    default: 1
  },
  
  // 创建时间
  createdAt: {
    type: Date,
    default: Date.now
  },
  
  // 更新时间
  updatedAt: {
    type: Date,
    default: Date.now
  }
}, {
  // 启用时间戳自动管理
  timestamps: true,
  // 禁用版本控制
  versionKey: false
});

// 创建复合唯一索引：部门ID + 小组名称
GroupSchema.index({ departmentId: 1, name: 1 }, { unique: true });

// 创建复合索引：状态 + 创建时间（用于状态查询和排序）
GroupSchema.index({ status: 1, createdAt: -1 });

// 创建复合索引：部门ID + 状态（用于部门下的小组查询）
GroupSchema.index({ departmentId: 1, status: 1 });

// 创建单字段索引：组长ID（用于组长查询）
GroupSchema.index({ leaderId: 1 });

/**
 * 保存前中间件
 * 自动设置更新时间
 */
GroupSchema.pre('save', function(next) {
  if (this.isModified() && !this.isNew) {
    this.updatedAt = new Date();
  }
  next();
});

/**
 * 更新前中间件
 * 自动设置更新时间
 */
GroupSchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
  this.set({ updatedAt: new Date() });
  next();
});

/**
 * 实例方法：转换为JSON格式
 * 返回安全的小组数据，排除敏感信息
 */
GroupSchema.methods.toJSON = function() {
  const groupObject = this.toObject();
  return {
    _id: groupObject._id,
    name: groupObject.name,
    description: groupObject.description,
    departmentId: groupObject.departmentId,
    leaderId: groupObject.leaderId,
    status: groupObject.status,
    createdAt: groupObject.createdAt,
    updatedAt: groupObject.updatedAt
  };
};

/**
 * 静态方法：根据小组名称查找小组
 * @param name 小组名称
 * @returns 小组文档或null
 */
GroupSchema.statics.findByName = function(name: string): Promise<IGroupDocument | null> {
  return this.findOne({ name: name.trim() }).exec();
};

/**
 * 静态方法：根据部门ID查找小组列表
 * @param departmentId 部门ID
 * @returns 小组文档数组
 */
GroupSchema.statics.findByDepartment = function(departmentId: mongoose.Types.ObjectId): Promise<IGroupDocument[]> {
  return this.find({ departmentId }).sort({ createdAt: -1 }).exec();
};

/**
 * 静态方法：根据组长ID查找小组
 * @param leaderId 组长ID
 * @returns 小组文档或null
 */
GroupSchema.statics.findByLeader = function(leaderId: mongoose.Types.ObjectId): Promise<IGroupDocument | null> {
  return this.findOne({ leaderId }).exec();
};

/**
 * 静态方法：根据状态查找小组列表
 * @param status 状态值
 * @returns 小组文档数组
 */
GroupSchema.statics.findByStatus = function(status: number): Promise<IGroupDocument[]> {
  return this.find({ status }).sort({ createdAt: -1 }).exec();
};

// 创建并导出小组模型
const Group = mongoose.model<IGroupDocument, IGroupModel>('Group', GroupSchema);

export default Group;